//
//	File: OyDirect3D9_VertexCache.cpp
//

#include "../OyGeneral/OyGeneral.h"
#include "OyDirect3D9.h"
#include "OyDirect3D9_VertexCache.h"
#include "OyDirect3D9_SkinManager.h"
#include "MaterialSystem\RenderBatch.h"
#include "MaterialSystem\MaterialRenderer.h"
#include "MaterialSystem\AbstractMaterial.h"
#include "MaterialSystem\MaterialProperties.h"


OyD3D9StaticBuffer::OyD3D9StaticBuffer() : BoundingBox(OyVector4D(0,0,0), OyVector4D(0,0,0))
{
	nStride = 0; nSBID = nSkinID = 0xFFFFFFFF;
	nNumVerts = nNumIndis = nNumTris = 0;
	pDecl = NULL; pVB = NULL; pIB = NULL;
}
OyD3D9StaticBuffer::~OyD3D9StaticBuffer()
{
	if( MaterialModifier.m_material )
		delete MaterialModifier.m_material;
	MaterialModifier.m_material = NULL;

	if( pVB )
	{
		pVB->Release();
		pVB = NULL;
	}
	if( pIB )
	{
		pIB->Release();
		pIB = NULL;
	}
}

OyD3D9VertexCacheManager::OyD3D9VertexCacheManager(	OySkinManager *pSkinManager,
									LPDIRECT3DDEVICE9 pDevice, OyDirect3D9 *pOyD3D9 ) :	
	m_UPOSCache(INIT_UPOS_VertexCache_NUM),
	m_UTEXCache(INIT_UTEX_VertexCache_NUM),
	m_UCOLORCache(INIT_UCOLOR_VertexCache_NUM),
	m_UPOSNORMALCOLORTEXCache(INIT_UPOSNORMALCOLORTEX_VertexCache_NUM)
{
	m_VertexCacheMaxID = 1;

	m_pDevice       = pDevice;
	m_pOyD3D9       = pOyD3D9;
	m_pSkinManager  = pSkinManager;

	for( int i=0; i<INIT_UPOS_VertexCache_NUM; i++ )
	{
		m_UPOSCache.Push(new OyD3D9VertexCache( MAX_UPOS_DBUFFERSIZE, 
												MAX_UPOS_DBUFFERSIZE, 
												sizeof(OY_UPOS_VERTEX_TYPE),
												this,
												m_pSkinManager,
												m_VertexCacheMaxID++, 
												m_pOyD3D9->GetVertexDeclaration(VID_UPOS) ));
	}
	for( int i=0; i<INIT_UTEX_VertexCache_NUM; i++ )
	{
		m_UTEXCache.Push(new OyD3D9VertexCache( MAX_UTEX_DBUFFERSIZE, 
												MAX_UTEX_DBUFFERSIZE, 
												sizeof(OY_UTEX_VERTEX_TYPE),
												this,
												m_pSkinManager,
												m_VertexCacheMaxID++, 
												m_pOyD3D9->GetVertexDeclaration(VID_UTEX) ));
	}
	for( int i=0; i<INIT_UCOLOR_VertexCache_NUM; i++ )
	{
		m_UCOLORCache.Push(new OyD3D9VertexCache(	MAX_UCOLOR_DBUFFERSIZE, 
													MAX_UCOLOR_DBUFFERSIZE, 
													sizeof(OY_UCOLOR_VERTEX_TYPE),
													this,
													m_pSkinManager,
													m_VertexCacheMaxID++, 
													m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR) ));
	}
	for( int i=0; i<INIT_UPOSNORMALCOLORTEX_VertexCache_NUM; i++ )
	{
		m_UPOSNORMALCOLORTEXCache.Push(new OyD3D9VertexCache(	MAX_UPOSNORMALCOLORTEX_DBUFFERSIZE, 
													MAX_UPOSNORMALCOLORTEX_DBUFFERSIZE, 
													sizeof(OY_UNORMALCOLORTEX_VERTEX_TYPE),
													this,
													m_pSkinManager,
													m_VertexCacheMaxID++, 
													m_pOyD3D9->GetVertexDeclaration(VID_UNORCOLTEX) ));
	}


	m_SyncCreateSBList[0].Append(new RingFIFO<DLCreateSB>(INIT_SYNC_SB_RESOURCE));
	m_SyncCreateSBList[1].Append(new RingFIFO<DLCreateSB>(INIT_SYNC_SB_RESOURCE));
	m_SyncDeleteSBList.Append(new RingFIFO<DLDeleteSB>(INIT_SYNC_SB_RESOURCE));
	CreateSBListWorkingID = 0;
}

OyD3D9VertexCacheManager::~OyD3D9VertexCacheManager()
{
	// Last Chance release all static buffers
	DoubleListIterator<OyD3D9StaticBuffer*> it = m_pSB.GetIterator();
	while( it.Valid() )
	{
		delete it.Item();
		it.Item() = NULL;
		it.Forth();
	}

	// free dynamic vertex caches
	for( int i=0; i<m_UPOSCache.Size(); i++ )
	{
		if( m_UPOSCache[i] )
			delete m_UPOSCache[i];
		m_UPOSCache[i] = NULL;
	}
	for( int i=0; i<m_UTEXCache.Size(); i++ )
	{
		if( m_UTEXCache[i] )		
			delete m_UTEXCache[i];		
		m_UTEXCache[i] = NULL;
	}
	for( int i=0; i<m_UCOLORCache.Size(); i++ )
	{
		if( m_UCOLORCache[i] )
			delete m_UCOLORCache[i];
		m_UCOLORCache[i] = NULL;
	}
	for( int i=0; i<m_UPOSNORMALCOLORTEXCache.Size(); i++ )
	{
		if( m_UPOSNORMALCOLORTEXCache[i] )
			delete m_UPOSNORMALCOLORTEXCache[i];
		m_UPOSNORMALCOLORTEXCache[i] = NULL;
	}

	DoubleListIterator<RingFIFO<DLCreateSB>*> it_syncCreateRes0 = m_SyncCreateSBList[0].GetIterator();
	while( it_syncCreateRes0.Valid() )
	{
		delete it_syncCreateRes0.Item();
		it_syncCreateRes0.Item() = NULL;
		it_syncCreateRes0.Forth();
	}
	DoubleListIterator<RingFIFO<DLCreateSB>*> it_syncCreateRes1 = m_SyncCreateSBList[1].GetIterator();
	while( it_syncCreateRes1.Valid() )
	{
		delete it_syncCreateRes1.Item();
		it_syncCreateRes1.Item() = NULL;
		it_syncCreateRes1.Forth();
	}
	DoubleListIterator<RingFIFO<DLDeleteSB>*> it_syncDelRes = m_SyncDeleteSBList.GetIterator();
	while( it_syncDelRes.Valid() )
	{
		delete it_syncDelRes.Item();
		it_syncDelRes.Item() = NULL;
		it_syncDelRes.Forth();
	}
}

void OyD3D9VertexCacheManager::OnDeviceLost(void)
{
	for( int i=0; i<m_UPOSCache.Size(); i++ )
	{
		if( m_UPOSCache[i] )
			m_UPOSCache[i]->OnDeviceLost();
	}
	for( int i=0; i<m_UTEXCache.Size(); i++ )
	{
		if( m_UTEXCache[i] )
			m_UTEXCache[i]->OnDeviceLost();
	}
	for( int i=0; i<m_UCOLORCache.Size(); i++ )
	{
		if( m_UCOLORCache[i] )
			m_UCOLORCache[i]->OnDeviceLost();
	}
	for( int i=0; i<m_UPOSNORMALCOLORTEXCache.Size(); i++ )
	{
		if( m_UPOSNORMALCOLORTEXCache[i] )
			m_UPOSNORMALCOLORTEXCache[i]->OnDeviceLost();
	}
}

void OyD3D9VertexCacheManager::OnDeviceReset(void)
{
	for( int i=0; i<m_UPOSCache.Size(); i++ )
	{
		if( m_UPOSCache[i] )
			m_UPOSCache[i]->OnDeviceReset();
	}
	for( int i=0; i<m_UTEXCache.Size(); i++ )
	{
		if( m_UTEXCache[i] )
			m_UTEXCache[i]->OnDeviceReset();
	}
	for( int i=0; i<m_UCOLORCache.Size(); i++ )
	{
		if( m_UCOLORCache[i] )
			m_UCOLORCache[i]->OnDeviceReset();
	}
	for( int i=0; i<m_UPOSNORMALCOLORTEXCache.Size(); i++ )
	{
		if( m_UPOSNORMALCOLORTEXCache[i] )
			m_UPOSNORMALCOLORTEXCache[i]->OnDeviceReset();
	}
}

/**
 * commot all dynamic buffers. Call this function if you want to force all
 * contents send to render batch to be drawn. Normally it will be called
 * before Rendering render batch.
 */
HRESULT OyD3D9VertexCacheManager::ForcedCommitAll(void)
{
	HRESULT hr = OY_OK;
	for( int i=0; i<m_UPOSCache.Count(); i++ )
	{
		if( !m_UPOSCache[i]->IsEmpty() )
			if( FAILED( m_UPOSCache[i]->Commit() ) )
				hr = OY_FAIL;
	}
	for( int i=0; i<m_UTEXCache.Count(); i++ )
	{
		if( !m_UTEXCache[i]->IsEmpty() )
			if( FAILED( m_UTEXCache[i]->Commit() ) )
				hr = OY_FAIL;
	}
	for( int i=0; i<m_UCOLORCache.Count(); i++ )
	{
		if( !m_UCOLORCache[i]->IsEmpty() )
			if( FAILED( m_UCOLORCache[i]->Commit() ) )
				hr = OY_FAIL;
	}
	for( int i=0; i<m_UPOSNORMALCOLORTEXCache.Count(); i++ )
	{
		if( !m_UPOSNORMALCOLORTEXCache[i]->IsEmpty() )
			if( FAILED( m_UPOSNORMALCOLORTEXCache[i]->Commit() ) )
				hr = OY_FAIL;
	}
	return hr;
}

/**
 * clear all dynamic buffers. 
 */
HRESULT	OyD3D9VertexCacheManager::ForcedClearAll(void)
{
	for( int i=0; i<m_UPOSCache.Count(); i++ )
	{
		if( !m_UPOSCache[i]->IsEmpty() )
			m_UPOSCache[i]->Clear();
	}
	for( int i=0; i<m_UTEXCache.Count(); i++ )
	{
		if( !m_UTEXCache[i]->IsEmpty() )
			m_UTEXCache[i]->Clear();
	}
	for( int i=0; i<m_UCOLORCache.Count(); i++ )
	{
		if( !m_UCOLORCache[i]->IsEmpty() )
			m_UCOLORCache[i]->Clear();
	}
	for( int i=0; i<m_UPOSNORMALCOLORTEXCache.Count(); i++ )
	{
		if( !m_UPOSNORMALCOLORTEXCache[i]->IsEmpty() )
			m_UPOSNORMALCOLORTEXCache[i]->Clear();			
	}

	return OY_OK;
}

void OyD3D9VertexCacheManager::DeferedClearAllStaticBuffer()
{
	DoubleListIterator<OyD3D9StaticBuffer*> it = m_pSB.GetIterator();
	while( it.Valid() )
	{
		OyD3D9StaticBuffer *pSB = it.Item();
		if( pSB )
			DeferedClearStaticBuffer( pSB->nSBID );
		it.Forth();
	}	
}


HRESULT OyD3D9VertexCacheManager::DeferedClearStaticBuffer( UINT nSBufferID )
{
	DLDeleteSB delSB;
	delSB.SBID = nSBufferID;

	DoubleListIterator<RingFIFO<DLDeleteSB>*> it = m_SyncDeleteSBList.GetIterator();
	while( it.Valid() )
	{
		if( it.Item()->getFreeSize() != 0 )
		{
			it.Item()->push(&delSB, 1);
			return OY_OK;
		}
		it.Forth();
	}

	RingFIFO<DLDeleteSB> *p = new RingFIFO<DLDeleteSB>(INIT_SYNC_SB_RESOURCE);
	p->push(&delSB, 1);
	m_SyncDeleteSBList.Append( p );

	return OY_OK;
}

void OyD3D9VertexCacheManager::DeferedSyncResource()
{
	static DLCreateSB newSB;
	static DLDeleteSB delSBID;

	// Delete Static Buffer
	DoubleListIterator<RingFIFO<DLDeleteSB>*> it_syncDelRes = m_SyncDeleteSBList.GetIterator();
	while( it_syncDelRes.Valid() )
	{
		while( it_syncDelRes.Item()->pop(&delSBID, 1) != 0 )
		{
			OyD3D9StaticBuffer *pSB = NULL;
			DoubleListIterator<OyD3D9StaticBuffer*> it = m_pSB.GetIterator();
			while( it.Valid() )
			{
				if( it.Item()->nSBID == delSBID.SBID )
				{
					pSB = it.Item();
					delete pSB;
					pSB = NULL;
					m_pSB.Remove(it);
				}
				else
					it.Forth();
			}
		}
		it_syncDelRes.Item()->clear();
		it_syncDelRes.Forth();
	}
		
	CreateSBListWorkingID = (CreateSBListWorkingID == 0) ? 1 : 0;
	// Create Static Buffer
	DoubleListIterator<RingFIFO<DLCreateSB>*> it_syncCreateRes = m_SyncCreateSBList[CreateSBListWorkingID].GetIterator();
	while( it_syncCreateRes.Valid() )
	{
		while( it_syncCreateRes.Item()->pop(&newSB, 1) != 0 )
		{
			UINT SBID = 0xFFFFFFFF;

			CreateStaticBuffer( 
				newSB.VertexType, 
				newSB.nSkinID, 
				newSB.nVertexNum,
				newSB.nIndexNum,
				newSB.pVerts,
				newSB.pIndis,
				&SBID );
		}
		it_syncCreateRes.Item()->clear();
		it_syncCreateRes.Forth();
	}

	return;
}

HRESULT	OyD3D9VertexCacheManager::DeferedCreateStaticBuffer( OY_VERTEXTYPE VertexType,
	UINT nSkinID, UINT nVertexNum, UINT nIndexNum, const void *pVerts, const WORD *pIndis ) 
{
	static DLCreateSB newSB;
	newSB.VertexType = VertexType;
	newSB.nSkinID = nSkinID;
	newSB.nVertexNum = nVertexNum;
	newSB.nIndexNum = nIndexNum;
	newSB.pVerts = pVerts;
	newSB.pIndis = pIndis;

	DoubleListIterator<RingFIFO<DLCreateSB>*> it_syncCreateRes = m_SyncCreateSBList[CreateSBListWorkingID].GetIterator();
	while( it_syncCreateRes.Valid() )
	{
		if( it_syncCreateRes.Item()->getFreeSize() != 0 )
		{
			it_syncCreateRes.Item()->push(&newSB, 1);
			return OY_OK;
		}
		it_syncCreateRes.Forth();
	}

	RingFIFO<DLCreateSB> *p = new RingFIFO<DLCreateSB>(INIT_SYNC_SB_RESOURCE);
	p->push(&newSB, 1);
	m_SyncCreateSBList[CreateSBListWorkingID].Append( p ); 

	return OY_OK;
}

/**
 * Create a static vertex/index buffer for the given data and returns
 * a handle to that buffer for later rendering processes.
 * -> IN:  OY_VERTEXTYPE - identify the vertex format used
 *         UINT        - skin that should be used
 *         UINT        - number of vertices to come
 *         UINT        - number of indices to come
 *         void        - pointer to vertex stream
 *         void        - pointer to index stream
 * -> OUT: UINT        - ID to the created StaticBuffer
 */
HRESULT	OyD3D9VertexCacheManager::CreateStaticBuffer( OY_VERTEXTYPE VertexType, 
	UINT nSkinID, UINT nVertexNum, UINT nIndexNum, 
	const void *pVerts, const WORD *pIndis, UINT *pnID )
{
	HRESULT hr;
	void *pData = NULL;
	static UINT S_SB_ID = 0;

	OyD3D9StaticBuffer *pNewSB = new OyD3D9StaticBuffer;
	pNewSB->nNumVerts = nVertexNum;
	pNewSB->nNumIndis = nIndexNum;
	pNewSB->nSkinID   = nSkinID;
	pNewSB->pIB       = NULL;
	pNewSB->pVB       = NULL;

	OySkin StaticBufferSkin = m_pSkinManager->GetSkin(pNewSB->nSkinID);
	
	// get size and format of vertex
	switch(VertexType) 
	{
	case VID_UPOS:
		{ 
			pNewSB->nStride = sizeof(OY_UPOS_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_UPOS);
		} break;
	case VID_UNORCOLTEX:
		{
			pNewSB->nStride = sizeof(OY_UNORMALCOLORTEX_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_UNORCOLTEX);
		} break;
	case VID_UTEX:
		{ 
			pNewSB->nStride = sizeof(OY_UTEX_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_UTEX);
		} break;
	case VID_UCOLOR:
		{
			pNewSB->nStride = sizeof(OY_UCOLOR_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR);
		} break;
	case VID_ANIM:
		{
			pNewSB->nStride = sizeof(OY_ANIM_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_ANIM);
		} break;
	case VID_THREETEX:
		{
			pNewSB->nStride = sizeof(OY_THREETEX_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_THREETEX);
		} break;
	case VID_UTAN: 
		{
			pNewSB->nStride = sizeof(OY_UTAN_VERTEX_TYPE); 
			pNewSB->pDecl = m_pOyD3D9->GetVertexDeclaration(VID_UTAN);
		} break;

	default:
		hr = OY_INVALIDID;
		goto create_error;
		break;
	}

	// create indexbuffer if needed
	if(nIndexNum > 0)
	{
		pNewSB->nNumTris = nIndexNum / 3;
		hr = m_pDevice->CreateIndexBuffer(
                    nIndexNum * sizeof(WORD),
                    D3DUSAGE_WRITEONLY,
                    D3DFMT_INDEX16,
                    D3DPOOL_MANAGED,
                    &(pNewSB->pIB), 
                    NULL);
		if(FAILED(hr))
		{
			hr = OY_CREATEBUFFER;
			goto create_error;
		}

		// fill the index buffer
		if( SUCCEEDED( pNewSB->pIB->Lock( 0, 0, (void**)(&pData), 0) ) )
		{
			memcpy(pData, pIndis, nIndexNum*sizeof(WORD));
			pNewSB->pIB->Unlock();
		}
		else
		{
			hr = OY_BUFFERLOCK;
			goto create_error;
		}
	}
	else
	{
		pNewSB->nNumTris = nVertexNum / 3;
		pNewSB->pIB = NULL;
	}

	// create vertex buffer
	hr = m_pDevice->CreateVertexBuffer(
                           nVertexNum * pNewSB->nStride,
                           D3DUSAGE_WRITEONLY,
                           0,
                           D3DPOOL_MANAGED,
                           &(pNewSB->pVB), 
                           NULL);
	if(FAILED(hr))
	{
		hr = OY_CREATEBUFFER;
		goto create_error;
	}

	// fill the vertex buffer
	if( SUCCEEDED( pNewSB->pVB->Lock( 0, 0, (void**)(&pData), 0) ) ) 
	{
		memcpy(pData, pVerts, nVertexNum*pNewSB->nStride);
		pNewSB->pVB->Unlock();
	}
	else
	{
		hr = OY_BUFFERLOCK;
		goto create_error;
	}

	(*pnID) = S_SB_ID;
	pNewSB->nSBID = S_SB_ID;
	S_SB_ID++;

	//pNewSB->MaterialModifier.m_material->GetRenderPass(0)->AddProperty(new TextureProperty(StaticBufferSkin.nTextureID[0], 0));
	GetOyMaterialSystem()->CommitAdditionalMaterial(pNewSB->MaterialModifier, &StaticBufferSkin);
	m_pSB.Append(pNewSB);


	return OY_OK;

create_error:
	delete pNewSB;
	pNewSB = NULL;
	return hr;
}

/**
 * Takes the vertex and index lists and sorts them into one fitting
 * vertex cache that features the same vertexID. Note that output of pixel
 * to any buffers is not immediately. 
 * -> IN: OY_VERTEXTYPE - vertex type to be processed
 *		  UINT		  - skin ID used for those vertices
 *        UINT        - number of vertices in this call
 *        UINT        - number of indices in this call
 *        void*       - array of vertices
 *        WORD*       - array of indices
 **/
HRESULT	OyD3D9VertexCacheManager::RenderDynamicBuffer(OY_VERTEXTYPE VertexType,
	UINT nSkinID, UINT nVertexNum, UINT nIndexNum, const void *pVerts, const WORD *pIndis )
{
	OyArrayStack<OyD3D9VertexCache*> *pCache = NULL;

	// which vertex type is to be processed?
	switch(VertexType)
	{
    case VID_UPOS:		{ pCache = &m_UPOSCache; } break;
    case VID_UTEX:		{ pCache = &m_UTEXCache; } break;
    case VID_UCOLOR:	{ pCache = &m_UCOLORCache; } break;
	case VID_UNORCOLTEX:{ pCache = &m_UPOSNORMALCOLORTEXCache; } break;
    case VID_ANIM:		/*{ pCache = &m_ANIMCache; } break;*/
    case VID_THREETEX:	/*{ pCache = &m_THREETEXCache; } break;*/
    case VID_UTAN:		/*{ pCache = &m_UTANCache; } break;*/
    default: 
		return OY_INVALIDID;
    }

	if( !pCache )
		return OY_INVALIDPARAM;

	for(int i=0; i<pCache->Count(); i++)
	{
		// first check if any cache uses same skin.
		if( (*pCache)[i]->IsUsedSkinID(nSkinID) )
		{
			if( (*pCache)[i]->IsCapacityEnough(nVertexNum, nIndexNum) )
				return (*pCache)[i]->Add(nVertexNum, nIndexNum, pVerts, pIndis);
		}
		if( (*pCache)[i]->IsEmpty() )
		{
			(*pCache)[i]->SetSkin(nSkinID);
			return (*pCache)[i]->Add(nVertexNum, nIndexNum, pVerts, pIndis);
		}
	}

	// Push new vertex cache
	OyD3D9VertexCache *pNewVC = NULL;
	// which vertex type is to be processed?
	switch(VertexType)
	{
    case VID_UPOS:		
		{ 
			pNewVC = new OyD3D9VertexCache(	MAX_UPOS_DBUFFERSIZE, 
											MAX_UPOS_DBUFFERSIZE, 
											sizeof(OY_UPOS_VERTEX_TYPE),
											this,
											m_pSkinManager,
											m_VertexCacheMaxID++, 
											m_pOyD3D9->GetVertexDeclaration(VID_UPOS));
			if( !pCache->Push(pNewVC) )
			{
				pCache->Resize(pCache->Size() + INIT_UPOS_VertexCache_NUM);
				pCache->Push(pNewVC);
			}
		} break;
    case VID_UTEX:		
		{ 
			pNewVC = new OyD3D9VertexCache( MAX_UTEX_DBUFFERSIZE, 
											MAX_UTEX_DBUFFERSIZE, 
											sizeof(OY_UTEX_VERTEX_TYPE),
											this,
											m_pSkinManager,
											m_VertexCacheMaxID++, 
											m_pOyD3D9->GetVertexDeclaration(VID_UTEX) );
			if( !pCache->Push(pNewVC) )
			{
				pCache->Resize(pCache->Size() + INIT_UTEX_VertexCache_NUM);
				pCache->Push(pNewVC);
			}
		} break;
    case VID_UCOLOR:	
		{ 
			pNewVC = new OyD3D9VertexCache(	MAX_UCOLOR_DBUFFERSIZE, 
											MAX_UCOLOR_DBUFFERSIZE, 
											sizeof(OY_UCOLOR_VERTEX_TYPE),
											this,
											m_pSkinManager,
											m_VertexCacheMaxID++, 
											m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR) );
			if( !pCache->Push(pNewVC) )
			{
				pCache->Resize(pCache->Size() + INIT_UCOLOR_VertexCache_NUM);
				pCache->Push(pNewVC);
			}
		} break;
	case VID_UNORCOLTEX:
    case VID_ANIM:
    case VID_THREETEX:
    case VID_UTAN:
    default: 
		return OY_INVALIDID;
    }

	return pNewVC->Add(nVertexNum, nIndexNum, pVerts, pIndis);
}

HRESULT	OyD3D9VertexCacheManager::RenderStaticBuffer( UINT nSBufferID )
{
	HRESULT hr = OY_OK;

	OyD3D9StaticBuffer *pSB = NULL;
	DoubleListIterator<OyD3D9StaticBuffer*> it = m_pSB.GetIterator();
	while( it.Valid() )
	{
		if( it.Item()->nSBID == nSBufferID )
		{
			pSB = it.Item();
			break;
		}
		it.Forth();
	}
	if( pSB == NULL )
		return OY_INVALIDPARAM;

	// Get correct Material info
	OySkin StaticBufferSkin = m_pSkinManager->GetSkin(pSB->nSkinID);
	
	// Update Texture
	GetOyMaterialSystem()->UpdateTextureMaterial(pSB->MaterialModifier, StaticBufferSkin.nTextureID[0], 0);
	
	// Commit this cache to RenderBatch
	if( StaticBufferSkin.bAlpha )
	{
		//transparent
		CTransparentRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter = pSB->BoundingBox.vcCenter;
		newRenderBatch.m_MatWorld.Identity();
		newRenderBatch.m_pSB = pSB;
		newRenderBatch.m_pVC = NULL;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushTransparentRenderBatch(newRenderBatch);
	}
	else if( StaticBufferSkin.bAlphaTest )
	{
		//alpha-test
		COpaqueAlphaTestRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter.Set(0,0,0);
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = pSB;
		newRenderBatch.m_pVC = NULL;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushAlphaTestRenderBatch(newRenderBatch);
	}
	else
	{
		//opaque
		COpaqueRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter.Set(0,0,0);
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = pSB;
		newRenderBatch.m_pVC = NULL;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushOpaqueRenderBatch(newRenderBatch);
	}
	
	return hr;
}

HRESULT	OyD3D9VertexCacheManager::RenderStaticBuffer( UINT nSBufferID, UINT SkinID )
{
	HRESULT hr = OY_OK;

	OyD3D9StaticBuffer *pSB = NULL;
	DoubleListIterator<OyD3D9StaticBuffer*> it = m_pSB.GetIterator();
	while( it.Valid() )
	{
		if( it.Item()->nSBID == nSBufferID )
		{
			pSB = it.Item();
			break;
		}
		it.Forth();
	}
	if( pSB == NULL )
		return OY_INVALIDPARAM;


	// Get correct Material info
	OySkin StaticBufferSkin = m_pSkinManager->GetSkin(SkinID);
	// Update Texture
	GetOyMaterialSystem()->UpdateTextureMaterial(pSB->MaterialModifier, StaticBufferSkin.nTextureID[0], 0);

	// Commit this cache to RenderBatch
	if( StaticBufferSkin.bAlpha )
	{
		//transparent
		CTransparentRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter.Set(0,0,0);
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = pSB;
		newRenderBatch.m_pVC = NULL;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushTransparentRenderBatch(newRenderBatch);
	}
	else if( StaticBufferSkin.bAlphaTest )
	{
		//alpha-test
		COpaqueAlphaTestRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter.Set(0,0,0);
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = pSB;
		newRenderBatch.m_pVC = NULL;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushAlphaTestRenderBatch(newRenderBatch);
	}
	else
	{
		//opaque
		COpaqueRenderBatch newRenderBatch;
		newRenderBatch.m_BatchType = CRenderBatch::eBatchOpaque;
		newRenderBatch.m_BBOXCenter.Set(0,0,0);
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = pSB;
		newRenderBatch.m_pVC = NULL;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushOpaqueRenderBatch(newRenderBatch);
	}
	return hr;
}

HRESULT	OyD3D9VertexCacheManager::RenderAllStaticBuffer()
{
	HRESULT hr = OY_OK;

	OyD3D9StaticBuffer *pSB = NULL;
	DoubleListIterator<OyD3D9StaticBuffer*> it = m_pSB.GetIterator();
	while( it.Valid() )
	{
		if( it.Item() )
		{
			pSB = it.Item();

			// Get correct Material info
			OySkin StaticBufferSkin = m_pSkinManager->GetSkin(pSB->nSkinID);
	
			// Update Texture
			GetOyMaterialSystem()->UpdateTextureMaterial(pSB->MaterialModifier, StaticBufferSkin.nTextureID[0], 0);
	
			// Commit this cache to RenderBatch
			if( StaticBufferSkin.bAlpha )
			{
				//transparent
				CTransparentRenderBatch newRenderBatch;
				newRenderBatch.m_BBOXCenter = pSB->BoundingBox.vcCenter;
				newRenderBatch.m_MatWorld.Identity();
				newRenderBatch.m_pSB = pSB;
				newRenderBatch.m_pVC = NULL;
				newRenderBatch.BuildQueueValue();
				GetMaterialRenderer()->PushTransparentRenderBatch(newRenderBatch);
			}
			else if( StaticBufferSkin.bAlphaTest )
			{
				//alpha-test
				COpaqueAlphaTestRenderBatch newRenderBatch;
				newRenderBatch.m_BBOXCenter.Set(0,0,0);
				newRenderBatch.m_MatWorld.Identity();	
				newRenderBatch.m_pSB = pSB;
				newRenderBatch.m_pVC = NULL;
				newRenderBatch.BuildQueueValue();
				GetMaterialRenderer()->PushAlphaTestRenderBatch(newRenderBatch);
			}
			else
			{
				//opaque
				COpaqueRenderBatch newRenderBatch;
				newRenderBatch.m_BBOXCenter.Set(0,0,0);
				newRenderBatch.m_MatWorld.Identity();	
				newRenderBatch.m_pSB = pSB;
				newRenderBatch.m_pVC = NULL;
				newRenderBatch.BuildQueueValue();
				GetMaterialRenderer()->PushOpaqueRenderBatch(newRenderBatch);
			}			
		}
		it.Forth();
	}
	return OY_OK;
}

HRESULT	OyD3D9VertexCacheManager::RenderPoints(	OY_VERTEXTYPE VertexType,
	UINT nVertexNum, const void	*pVerts, const OyColor *pColor )
{
	int nStride;
	D3DMATERIAL9 mtrl;
	if(pColor)
	{
		memset(&mtrl, 0, sizeof(D3DMATERIAL9));
		mtrl.Diffuse.r = mtrl.Ambient.r = pColor->fR;
		mtrl.Diffuse.g = mtrl.Ambient.g = pColor->fG;
		mtrl.Diffuse.b = mtrl.Ambient.b = pColor->fB;
		mtrl.Diffuse.a = mtrl.Ambient.a = pColor->fA;
		m_pDevice->SetMaterial(&mtrl);
	}
	m_pDevice->SetTexture(0, NULL);

	switch(VertexType)
	{
		case VID_UPOS:
		{ 
			nStride = sizeof(OY_UPOS_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UPOS) );
		}
		break;
		case VID_UNORCOLTEX:
		{
			nStride = sizeof(OY_UNORMALCOLORTEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UNORCOLTEX) );
		}
		break;
		case VID_UTEX:
		{
			nStride = sizeof(OY_UTEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UTEX) );
		}
		break;
		case VID_UCOLOR:
		{
			nStride = sizeof(OY_UCOLOR_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR) );
		}
		break;
		case VID_ANIM:
		{
			nStride = sizeof(OY_ANIM_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_ANIM) );
		}
		break;
		case VID_THREETEX:
		{
			nStride = sizeof(OY_THREETEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_THREETEX) );
		}
		break;
		case VID_UTAN:
		{
			nStride = sizeof(OY_UTAN_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UTAN) );
		}
		break;
		default: 
			return OY_INVALIDID;
	}
	m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	// render list of points
	m_pDevice->DrawPrimitiveUP(D3DPT_POINTLIST, nVertexNum, pVerts, nStride);

	m_pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

	return OY_OK;
}

HRESULT	OyD3D9VertexCacheManager::RenderLines( OY_VERTEXTYPE   VertexType,
	UINT nVertexNum, const void	*pVerts, const OyColor *pColor,	bool bStrip )
{
	int nStride;
	D3DMATERIAL9 mtrl;
	if(pColor)
	{
		memset(&mtrl, 0, sizeof(D3DMATERIAL9));
		mtrl.Diffuse.r = mtrl.Ambient.r = pColor->fR;
		mtrl.Diffuse.g = mtrl.Ambient.g = pColor->fG;
		mtrl.Diffuse.b = mtrl.Ambient.b = pColor->fB;
		mtrl.Diffuse.a = mtrl.Ambient.a = pColor->fA;
		m_pDevice->SetMaterial(&mtrl);
	}
	m_pDevice->SetTexture(0, NULL);

	switch(VertexType)
	{
		case VID_UPOS:
		{ 
			nStride = sizeof(OY_UPOS_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UPOS) );
		}
		break;
		case VID_UNORCOLTEX:
		{
			nStride = sizeof(OY_UNORMALCOLORTEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UNORCOLTEX) );
		}
		break;
		case VID_UTEX:
		{
			nStride = sizeof(OY_UTEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UTEX) );
		}
		break;
		case VID_UCOLOR:
		{
			nStride = sizeof(OY_UCOLOR_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR) );
		}
		break;
		case VID_ANIM:
		{
			nStride = sizeof(OY_ANIM_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_ANIM) );
		}
		break;
		case VID_THREETEX:
		{
			nStride = sizeof(OY_THREETEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_THREETEX) );
		}
		break;
		case VID_UTAN:
		{
			nStride = sizeof(OY_UTAN_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UTAN) );
		}
		break;
		default: 
			return OY_INVALIDID;
	}

	m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	// render list of lines
	if(!bStrip)
	{
		m_pDevice->DrawPrimitiveUP(D3DPT_LINELIST, nVertexNum/2, pVerts, nStride); 
	}
	else
	{
		m_pDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, nVertexNum-1, pVerts, nStride);
	}

	m_pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

	return OY_OK;
}

HRESULT	OyD3D9VertexCacheManager::RenderLine( const float *fStart, const float *fEnd, const OyColor *pColor )
{
	OY_UCOLOR_VERTEX_TYPE pVerts[2];
	if(!pColor)
		return OY_INVALIDPARAM;

	// set coordinates
	pVerts[0].x = fStart[0];
	pVerts[0].y = fStart[1];
	pVerts[0].z = fStart[2];
	pVerts[1].x = fEnd[0];
	pVerts[1].y = fEnd[1];
	pVerts[1].z = fEnd[2];
	pVerts[0].VertexColor = pVerts[1].VertexColor = 
		D3DCOLOR_COLORVALUE( pColor->fR, pColor->fG, pColor->fB, pColor->fA );

	D3DMATERIAL9 mtrl;
	memset(&mtrl, 0, sizeof(D3DMATERIAL9));
	mtrl.Diffuse.r = mtrl.Ambient.r = pColor->fR;
	mtrl.Diffuse.g = mtrl.Ambient.g = pColor->fG;
	mtrl.Diffuse.b = mtrl.Ambient.b = pColor->fB;
	mtrl.Diffuse.a = mtrl.Ambient.a = pColor->fA;

	m_pDevice->SetMaterial(&mtrl);
	m_pDevice->SetTexture(0,NULL);

	m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR) );
	m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

	m_pDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, pVerts, sizeof(OY_UCOLOR_VERTEX_TYPE));
	
	m_pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

	return OY_OK;
}

HRESULT	OyD3D9VertexCacheManager::RenderTriangles( OY_VERTEXTYPE VertexType,
		UINT nVertexNum, UINT nIndexNum, const void	*pVerts, const WORD *pIndis,
		const UINT MaterialID, const UINT ModifierID, char* CustomMaterialStr, const UINT SkinID )
{
	int nStride;

	if( CustomMaterialStr )
		GetOyMaterialSystem()->LoadCustomMaterials(CustomMaterialStr);

	switch(VertexType)
	{
		case VID_UPOS:
		{ 
			nStride = sizeof(OY_UPOS_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UPOS) );
		}
		break;
		case VID_UNORCOLTEX:
		{
			nStride = sizeof(OY_UNORMALCOLORTEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UNORCOLTEX) );
		}
		break;
		case VID_UTEX:
		{
			nStride = sizeof(OY_UTEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UTEX) );
		}
		break;
		case VID_UCOLOR:
		{
			nStride = sizeof(OY_UCOLOR_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UCOLOR) );
		}
		break;
		case VID_ANIM:
		{
			nStride = sizeof(OY_ANIM_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_ANIM) );
		}
		break;
		case VID_THREETEX:
		{
			nStride = sizeof(OY_THREETEX_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_THREETEX) );
		}
		break;
		case VID_UTAN:
		{
			nStride = sizeof(OY_UTAN_VERTEX_TYPE);
			m_pDevice->SetVertexDeclaration( m_pOyD3D9->GetVertexDeclaration(VID_UTAN) );
		}
		break;
		default: 
			return OY_INVALIDID;
	}

	OySkin TriangleSkin = m_pSkinManager->GetSkin(SkinID);
	if( TriangleSkin.nTextureID[0] != 0xFFFFFFFF )
		m_pDevice->SetTexture(0, (LPDIRECT3DTEXTURE9)m_pSkinManager->GetOyTextureData(TriangleSkin.nTextureID[0]));
	if( TriangleSkin.nTextureID[1] != 0xFFFFFFFF )
		m_pDevice->SetTexture(1, (LPDIRECT3DTEXTURE9)m_pSkinManager->GetOyTextureData(TriangleSkin.nTextureID[1]));

	if( (ModifierID != 0xFFFFFFFF) && (ModifierID < OyMaterialSystem::eModifier_Unknow) )
	{
		OyMaterialSystem::MaterialList &Mod_List = GetOyMaterialSystem()->GetModifierList();
		const OyMaterialSystem::D3D9MaterialInfo &Modifier_info = Mod_List[ModifierID];
		GetMaterialRenderer()->PushMaterial(Modifier_info.m_material, Modifier_info.m_material->GetMergeMode());
	}

	if( (MaterialID != 0xFFFFFFFF) && (MaterialID < OyMaterialSystem::eMaterial_Unknow) )
	{
		OyMaterialSystem::MaterialList &Mat_List = GetOyMaterialSystem()->GetMaterialList();
		const OyMaterialSystem::D3D9MaterialInfo &Material_info = Mat_List[MaterialID];
		GetMaterialRenderer()->PushMaterial(Material_info.m_material, Material_info.m_material->GetMergeMode());
	}

	int PassNum = GetMaterialRenderer()->ComputeMaterialPass();
	for( int PassIdx = 0; PassIdx < PassNum; ++PassIdx )
	{
		GetMaterialRenderer()->OnePassPreRenderMaterial(PassIdx);

		m_pDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, nVertexNum, nIndexNum/3, 
			pIndis, D3DFMT_INDEX16, pVerts, nStride);

		GetMaterialRenderer()->OnePassPostRenderMaterial(PassIdx);
	}

	if( (MaterialID != 0xFFFFFFFF) && (MaterialID < OyMaterialSystem::eMaterial_Unknow) )
	{
		GetMaterialRenderer()->PopMaterial();
	}
	if( (ModifierID != 0xFFFFFFFF) && (ModifierID < OyMaterialSystem::eModifier_Unknow) )
	{
		GetMaterialRenderer()->PopMaterial();
	}
	
	if( TriangleSkin.nTextureID[0] != 0xFFFFFFFF )
		m_pDevice->SetTexture(0, NULL);
	if( TriangleSkin.nTextureID[1] != 0xFFFFFFFF )
		m_pDevice->SetTexture(1, NULL);

	return OY_OK;
}


/////////////////////////////////////////////////////////////////////////////////////////

OyD3D9VertexCache::OyD3D9VertexCache( UINT nVertsMax, UINT nIndisMax, UINT nStride,
	OyD3D9VertexCacheManager *pVCManager, OySkinManager *pSkinManager, DWORD dwID, LPDIRECT3DVERTEXDECLARATION9 pDecl )
	: m_BoundingBox(OyVector4D(0,0,0), OyVector4D(0,0,0))
{
	HRESULT hr;

	m_pVCManager        = pVCManager;
	m_pSkinManager		= pSkinManager;
	m_nNumVertsMax		= nVertsMax;
	m_nNumIndisMax		= nIndisMax;
	m_nNumVerts			= 0;
	m_nNumIndis			= 0;
	m_dwVertexCacheID	= dwID;
	m_nStride			= nStride;
	m_pDecl				= pDecl;

	m_SkinID			= 0xFFFFFFFF;

	m_bCommited			= false;

	// create the buffers
	m_pVB = NULL;
	m_pIB = NULL;

	hr = m_pVCManager->GetDevice()->CreateVertexBuffer( m_nNumVertsMax * m_nStride,
													D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
													0, D3DPOOL_DEFAULT,	&m_pVB, NULL );
	if(FAILED(hr)) 
		m_pVB = NULL;

	hr = m_pVCManager->GetDevice()->CreateIndexBuffer( m_nNumIndisMax * sizeof(WORD),
													D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
													D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pIB, NULL );
	if(FAILED(hr)) 
		m_pIB = NULL;
}

OyD3D9VertexCache::~OyD3D9VertexCache(void)
{
	if(m_pVB) 
	{
		m_pVB->Release();
		m_pVB = NULL;
	}
	if(m_pIB)
	{
		m_pIB->Release();
		m_pIB = NULL;
	}
	if( m_MaterialModifier.m_material )
	{
		delete m_MaterialModifier.m_material;
		m_MaterialModifier.m_material = NULL;
	}
}

void OyD3D9VertexCache::OnDeviceLost(void)
{
	if(m_pVB) 
	{
		m_pVB->Release();
		m_pVB = NULL;
	}
	if(m_pIB)
	{
		m_pIB->Release();
		m_pIB = NULL;
	}
}

void OyD3D9VertexCache::OnDeviceReset(void)
{
	HRESULT hr;
	hr = m_pVCManager->GetDevice()->CreateVertexBuffer( m_nNumVertsMax * m_nStride,
													D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
													0, D3DPOOL_DEFAULT,	&m_pVB, NULL );
	if(FAILED(hr)) 
		m_pVB = NULL;

	hr = m_pVCManager->GetDevice()->CreateIndexBuffer( m_nNumIndisMax * sizeof(WORD),
													D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
													D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pIB, NULL );
	if(FAILED(hr)) 
		m_pIB = NULL;
}

/**
 * Set the given skin for the given stage.
 */
void OyD3D9VertexCache::SetSkin(UINT SkinID)
{
	// if a new texture is coming, flush all content of
	// the cache because that is using other textures
	if( !IsUsedSkinID(SkinID) )
	{
		// New SkinID so commit it
		if( !IsEmpty() ) 
			Commit();
      
		m_SkinID = SkinID;
	}
}

/**
 * Fill data into the cache. If the cache is full it will be commited to render batch.
 * If no Indexlist is used set indexlist parameter to NULL.
 * -> IN: UINT  - number of vertices in list
 *        UINT  - number of indices in list
 *        void* - pointer to vertex list
 *        WORD* - pointer to index list
 */
HRESULT OyD3D9VertexCache::Add(UINT nVertexNum, UINT nIndexNum, const void *pVerts, const WORD *pIndices) 
{
	BYTE *tmp_pVerts = NULL;         // pointer to VB memory
	WORD *tmp_pIndis = NULL;         // pointer to IB memory
   
	int nSizeV = m_nStride * nVertexNum;
	int nSizeI = sizeof(WORD) * nIndexNum;

	int nPosV = 0;
	int nPosI = 0;
	DWORD dwFlags = 0;

	// lists will never fit into this cache
	if(nVertexNum > m_nNumVertsMax || nIndexNum > m_nNumIndisMax)
		return OY_BUFFERSIZE;

	// cache is already full, so commit it
	if( (nVertexNum + m_nNumVerts > m_nNumVertsMax) ||
		(nIndexNum + m_nNumIndis > m_nNumIndisMax) )
	{
		if( Commit() != OY_OK)
		{
			OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: Commit() failed");
			return OY_FAIL;
		}
	}

	// if nothing is in buffer discard content
	if(m_nNumVerts == 0) 
	{
		nPosV = nPosI = 0;
		dwFlags = D3DLOCK_DISCARD;
	}	
	else	// else just append data without overwrites
	{
		nPosV = m_nStride * m_nNumVerts;
		nPosI = sizeof(WORD) * m_nNumIndis;
		dwFlags = D3DLOCK_NOOVERWRITE;
    }
          
	// now lock buffers
	if( FAILED(m_pVB->Lock(nPosV, nSizeV, (void**)&tmp_pVerts, dwFlags)) )
		return OY_BUFFERLOCK;
	if( FAILED(m_pIB->Lock(nPosI, nSizeI, (void**)&tmp_pIndis, dwFlags)) )
	{
		m_pVB->Unlock();
		return OY_BUFFERLOCK;
	}

	// copy vertex data into the buffer
	memcpy(tmp_pVerts, pVerts, nSizeV);

	// copy indices into the buffer
	int nBase = m_nNumVerts;
	if( !pIndices ) 
		nIndexNum = nVertexNum;

	for(UINT i=0; i<nIndexNum; i++)
	{
		if(pIndices != NULL)
			tmp_pIndis[i] = pIndices[i] + nBase;
		else
			tmp_pIndis[i] = i + nBase;
		m_nNumIndis++;
	}

	// add to count
	m_nNumVerts += nVertexNum;

	// unlock buffers
	m_pVB->Unlock();
	m_pIB->Unlock();

	return OY_OK;
}


/**
 * Send the content of the cache to the renderbatch.
 */
HRESULT OyD3D9VertexCache::Commit()
{
	HRESULT hr = OY_FAIL;

	// Have commited? OR anything to do at all?
	if( m_nNumVerts <= 0 || m_bCommited )
		return OY_OK;

	// Get correct Material info
	OySkin DynamicBufferSkin = m_pSkinManager->GetSkin(GetSkinID());

	// Set correct MaterialModifier

	//m_MaterialModifier.m_material->GetRenderPass(0)->AddProperty(new TextureProperty(DynamicBufferSkin.nTextureID[0], 0));
	GetOyMaterialSystem()->CommitAdditionalMaterial(m_MaterialModifier, &DynamicBufferSkin);
	
	// Commit this cache to RenderBatch
	if( DynamicBufferSkin.bAlpha )
	{
		//transparent
		CTransparentRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter = m_BoundingBox.vcCenter;
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = NULL;
		newRenderBatch.m_pVC = this;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushTransparentRenderBatch(newRenderBatch);
	}
	else if( DynamicBufferSkin.bAlphaTest )
	{
		//alpha-test
		COpaqueAlphaTestRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter = m_BoundingBox.vcCenter;
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = NULL;
		newRenderBatch.m_pVC = this;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushAlphaTestRenderBatch(newRenderBatch);
	}
	else
	{
		//opaque
		COpaqueRenderBatch newRenderBatch;
		newRenderBatch.m_BBOXCenter = m_BoundingBox.vcCenter;
		newRenderBatch.m_MatWorld.Identity();	
		newRenderBatch.m_pSB = NULL;
		newRenderBatch.m_pVC = this;
		newRenderBatch.BuildQueueValue();
		GetMaterialRenderer()->PushOpaqueRenderBatch(newRenderBatch);
	}

	m_bCommited = true;
	return hr;
}

void OyD3D9VertexCache::Clear(void)
{
	m_SkinID = 0xFFFFFFFF;
	m_nNumVerts = 0;
	m_nNumIndis = 0;
	memset( &m_BoundingBox, 0, sizeof(OyAABB) );
	m_MaterialModifier.Reset();
	m_bCommited = false;
}

